package main

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	alertv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/alert/v1"
	sharedconfig "github.com/devops-smartbot/devops-smartbot/shared/config"
	"github.com/devops-smartbot/devops-smartbot/shared/logger"
	"github.com/devops-smartbot/devops-smartbot/services/alert-service/internal/config"
	grpcserver "github.com/devops-smartbot/devops-smartbot/services/alert-service/internal/grpc"
	"github.com/devops-smartbot/devops-smartbot/services/alert-service/internal/repository"
	"github.com/devops-smartbot/devops-smartbot/services/alert-service/internal/service"
	"github.com/devops-smartbot/devops-smartbot/services/alert-service/internal/webhook"
	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

func main() {
	cfg := sharedconfig.MustLoad(os.Getenv("CONFIG_FILE"))
	log, err := logger.Init(cfg.App.Name, cfg.App.LogLevel)
	if err != nil {
		panic(fmt.Errorf("logger init: %w", err))
	}
	defer log.Sync() //nolint:errcheck

	serviceCfg := config.FromShared(cfg)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	mongoClient, err := mongo.Connect(ctx, options.Client().ApplyURI(serviceCfg.MongoURI))
	if err != nil {
		log.Fatal("mongo connect failed", zap.Error(err))
	}
	defer mongoClient.Disconnect(context.Background())

	repo := repository.NewMongoRepository(mongoClient.Database(serviceCfg.MongoDatabase))
	alertSvc := service.NewAlertService(repo)

	// Get notification service address from environment
	notificationAddr := os.Getenv("NOTIFICATION_SERVICE_ADDR")
	if notificationAddr == "" {
		notificationAddr = "notification-service:50053" // Default for Docker
	}

	// Create webhook handler with notification service
	webhookHandler := webhook.NewHandler(repo, log, notificationAddr)
	defer webhookHandler.Close()

	// Start HTTP server for webhooks
	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Recovery())
	router.POST("/webhook/alertmanager", webhookHandler.HandleAlertmanagerWebhook)

	httpServer := &http.Server{
		Addr:    fmt.Sprintf(":%d", serviceCfg.HTTPPort),
		Handler: router,
	}

	go func() {
		log.Info("alert-service HTTP webhook server listening", zap.Int("port", serviceCfg.HTTPPort))
		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatal("http serve failed", zap.Error(err))
		}
	}()

	// Start gRPC server
	grpcServer := grpc.NewServer(grpc.ChainUnaryInterceptor())
	alertv1.RegisterAlertServiceServer(grpcServer, grpcserver.New(alertSvc))

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", serviceCfg.GRPCPort))
	if err != nil {
		log.Fatal("failed to listen", zap.Error(err))
	}

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	go func() {
		log.Info("alert-service gRPC listening", zap.Int("port", serviceCfg.GRPCPort))
		if err := grpcServer.Serve(listener); err != nil {
			log.Fatal("grpc serve failed", zap.Error(err))
		}
	}()

	<-ctx.Done()
	log.Info("shutting down alert-service")

	// Gracefully shutdown HTTP server
	shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer shutdownCancel()
	if err := httpServer.Shutdown(shutdownCtx); err != nil {
		log.Error("http server shutdown error", zap.Error(err))
	}

	// Gracefully stop gRPC server
	grpcServer.GracefulStop()
}
